home *** CD-ROM | disk | FTP | other *** search
/ STraTOS 1997 April & May / STraTOS 1 - 1997 April & May.iso / CD01 / INTERNET / SITES / GRAHAM / XA_6S.ZIP / SOURCE / ENTRIES.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-23  |  6.0 KB  |  284 lines

  1. /*
  2.  * Directory access --- The POSIX way (I hope <g>)
  3.  *
  4.  * Note: if you're doing something recursive, ignore
  5.  * files "." and "..".
  6.  *
  7.  * W/ 1996 by Eero Tamminen, t150315@cc.tut.fi
  8.  * Extended by Craig
  9.  */
  10. #include <stdlib.h>            /* memory stuff */
  11. #include <sys/stat.h>            /* file statistics */
  12. #include <dirent.h>            /* directory stuff */
  13. #include <string.h>            /* string stuff */
  14. #include <unistd.h>
  15. #include "entries.h"            /* directory entry stuff */
  16. #include "xa_defs.h"
  17. #include "xa_types.h"
  18. #include "xa_globl.h"
  19.  
  20. static Lists NameList={NULL,NULL};    /* sorted name lists for listboxes */
  21. static Entry *EntryStart;        /* first directory entry */
  22. static char *MemEnd;            /* last allocated block */
  23. static int Dirs, Files;            /* number of entries */
  24.  
  25.  
  26. /* get directory entry information and copy it into memory */
  27. static void get_stats(char *name, Entry *current)
  28. {
  29.   struct stat st;
  30.  
  31.   /* get file information */
  32.   if(stat(name, &st) < 0)
  33.   {
  34.     current->size = 0;
  35.     current->flags = 0;
  36.   }
  37.   else
  38.   {
  39.     current->size = st.st_size;
  40.     current->flags = 0;
  41.  
  42.     if (st.st_mode & S_IFLNK)        /* ++cg[6/9/96]: Show sym links in entries */
  43.     {
  44.         current->flags |= FLAG_LINK;
  45.     }
  46.      
  47.     if(S_ISDIR(st.st_mode))
  48.     {
  49.       current->flags |= FLAG_DIR;
  50.       Dirs++;
  51.     }else{
  52.       if (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))    /* ++cg[6/9/96]: Show files that are executable */
  53.         current->flags |= FLAG_EXECUTABLE;
  54.         
  55.       Files++;
  56.     }
  57.  
  58.     /* set other flags */
  59.   }
  60.   /* copy dir entry name */
  61.   strcpy((char*)(current+1), name);
  62. }
  63.  
  64. /* read all the directory entries + handle memory allocation */
  65. Entry *read_entries(char *dir)
  66. {
  67.   char *new_block;
  68.   struct dirent *entry;
  69.   Entry *current, *prev;
  70.   int length, mem_left;
  71.   char *olddir;
  72.   DIR *dfd;
  73.  
  74.     DIAGS(("read_entries\n"));
  75.     DIAGS(("dir=%s\n",dir));
  76.  
  77.   olddir = getcwd(0, PATH_MAX);
  78.   chdir(dir);
  79.     
  80.   if(!(dfd = opendir(".")))
  81.     return 0;
  82.  
  83.   if(!(MemEnd = malloc(BLOCK_SIZE)))
  84.   {
  85.         chdir(olddir);
  86.         free(olddir);
  87.     closedir(dfd);
  88.     return 0;
  89.   }
  90.   
  91.   *(char **)MemEnd = NULL;            /* this is the first block */
  92.   EntryStart = (Entry *)(MemEnd + sizeof(char *));
  93.   mem_left = BLOCK_SIZE - sizeof(char *);
  94.   current = prev = EntryStart;
  95.   Files = Dirs = 0;
  96.  
  97.   while((entry = readdir(dfd)))
  98.   {
  99.     length = sizeof(Entry) + strlen(entry->d_name);
  100.     length = (length + POINTER_ALIGN) & ~(POINTER_ALIGN-1);
  101.  
  102.     /* allocate more memory if needed */
  103.     if(mem_left < length)
  104.     {
  105.       if(!(new_block = malloc(BLOCK_SIZE)))
  106.     break;                    /* out of memory */
  107.  
  108.       *(char **)new_block = MemEnd;
  109.       current = (Entry *)(new_block + sizeof(char *));
  110.       mem_left = BLOCK_SIZE - sizeof(char *);
  111.       MemEnd = new_block;
  112.     }
  113.     prev->next = current;
  114.     prev = current;
  115.     get_stats(entry->d_name, current);
  116.     current = (Entry *)((char *)current + length);
  117.     mem_left -= length;
  118.   }
  119.   prev->next = NULL;
  120.   closedir(dfd);
  121.   chdir(olddir);
  122.   free(olddir);
  123.   return EntryStart;
  124. }
  125.  
  126. static int compare(const void *a, const void *b)
  127. {
  128.   return strcmp(*(char**)a, *(char**)b);
  129. }
  130.  
  131. /*
  132.     Pattern matching
  133.     - if you want better filtering of files, put the code here.....
  134.     
  135.     Valid patterns are:
  136.         ?      Any single char
  137.         *      A string of any char
  138.         !X     Any char except for X
  139.         [abcd] One of (any one of a,b,c or d)
  140.     Examples:
  141.         *      All files in dir
  142.         a*     All files begining with 'a'
  143.         *.o    All '.o' files
  144.         *.!o   All files not ending in '.o' 
  145.         !z*.?  All files not starting with 'z', and having a single character extension
  146.         *.[co] All '.o' and '.c' files
  147. */
  148. short match_pattern(char *t, char *pat)
  149. {
  150.     short valid=1;
  151.     
  152.     while((valid)&&((*t)&&(*pat)))
  153.     {
  154.         switch(*pat)
  155.         {
  156.             case '?':            /* Any character */
  157.                 t++;
  158.                 pat++;
  159.                 break;
  160.             case '*':            /* String of any character */
  161.                 pat++;
  162.                 while((*t)&&(*t!=*pat))
  163.                     t++;
  164.                 break;
  165.             case '!':            /* !X means any character but X */
  166.                 if (*t!=pat[1])
  167.                 {
  168.                     t++;
  169.                     pat+=2;
  170.                 }else{
  171.                     valid=0;
  172.                 }
  173.                 break;
  174.             case '[':            /* [<chars>] means any one of <chars> */
  175.                 while((*(++pat)!=']')&&(*t!=*pat));
  176.                 
  177.                 if (*pat==']')
  178.                     valid=0;
  179.                 
  180.                 break;
  181.                         
  182.             default:
  183.                 if (*t==*pat)
  184.                 {
  185.                     t++;
  186.                     pat++;
  187.                 }else{
  188.                     valid=0;
  189.                 }
  190.                 break;
  191.             }
  192.     }
  193.     
  194.     if ((valid)&&(*t==*pat))
  195.     {
  196.         return 1;
  197.     }else{
  198.         return 0;
  199.     }
  200. }
  201.  
  202. /* 
  203.     divide directory entries into subdirectories & files and sort both 
  204.     ++cg[16/9/96]:retrofitted the pattern matching (glob) code
  205. */
  206. Lists *sort_entries(char *mask)
  207. {
  208.   Entry *current = EntryStart;
  209.   char **dirlist, **filelist;
  210.  
  211.   if(Dirs + Files <= 0)
  212.     return 0;
  213.  
  214.   dirlist = NameList.dirs = malloc((Dirs+1) * sizeof(char*));
  215.   if(!dirlist)
  216.     return 0;
  217.   filelist = NameList.files = malloc((Files+1) * sizeof(char*));
  218.   if(!filelist)
  219.   {
  220.     free(dirlist);
  221.     NameList.dirs = 0;
  222.     return 0;
  223.   }
  224.  
  225.   DIAGS(("sorting\n"));
  226.   NameList.num_dirs=0;
  227.   NameList.num_files=0;
  228.  
  229.   do
  230.   {
  231.     if(current->flags & FLAG_DIR)
  232.     {
  233.       *(dirlist++) = (char *)(current+1);
  234.       NameList.num_dirs++;
  235.     }else{
  236.       if (match_pattern((char *)(current+1),mask))    /* ++cg: match the pattern */
  237.       {
  238.         *(filelist++) = (char *)(current+1);
  239.         NameList.num_files++;
  240.       }else{
  241.         Files--;
  242.       }
  243.     }
  244.     current = current->next;
  245.   } while(current);
  246.   *filelist = NULL;
  247.   *dirlist = NULL;
  248.  
  249. #if FILESELECTOR_QSORT
  250.   if (Dirs)
  251.     qsort(NameList.dirs, Dirs, sizeof(char*), compare);
  252.   if (Files)
  253.     qsort(NameList.files, Files, sizeof(char*), compare);
  254. #endif
  255.  
  256.   return &NameList;
  257. }
  258.  
  259. /* free all the allocated spaces */
  260. void free_entries(void)
  261. {
  262.   char *previous;
  263.  
  264.   /* free lists */
  265.   if(NameList.dirs)
  266.   {
  267.     free(NameList.dirs);
  268.     NameList.dirs = 0;
  269.   }
  270.   if(NameList.files)
  271.   {
  272.     free(NameList.files);
  273.     NameList.files = 0;
  274.   }
  275.  
  276.   /* free blocks */
  277.   do
  278.   {
  279.     previous = *(char **)MemEnd;
  280.     free(MemEnd);
  281.     MemEnd = previous;
  282.   } while(MemEnd);
  283. }
  284.